//! VS Code terminal detection and automatic extension installation

use std::process::Command;

/// Checks if running in VS Code terminal
///
/// Detects VS Code by checking for environment variables that are set
/// when running in the VS Code integrated terminal.
pub fn is_vscode_terminal() -> bool {
    std::env::var("TERM_PROGRAM")
        .map(|val| val == "vscode")
        .unwrap_or(false)
        || std::env::var("VSCODE_PID").is_ok()
        || std::env::var("VSCODE_GIT_ASKPASS_NODE").is_ok()
        || std::env::var("VSCODE_GIT_IPC_HANDLE").is_ok()
}

/// Checks if the Forge VS Code extension is installed
///
/// Checks VS Code's extension list to see if ForgeCode.forge-vscode is
/// installed.
pub fn is_extension_installed() -> bool {
    // Try to list installed extensions
    if let Ok(output) = Command::new("code").arg("--list-extensions").output()
        && output.status.success()
        && let Ok(extensions) = String::from_utf8(output.stdout)
    {
        return extensions
            .lines()
            .any(|line| line.trim() == "ForgeCode.forge-vscode");
    }
    false
}

/// Attempts to install the Forge VS Code extension silently
///
/// Returns Ok(true) if installation was successful, Ok(false) if it failed,
/// or Err if the command couldn't be executed.
pub fn install_extension() -> Result<bool, std::io::Error> {
    let output = Command::new("code")
        .arg("--install-extension")
        .arg("ForgeCode.forge-vscode")
        .arg("--force")
        .output()?;

    Ok(output.status.success())
}

/// Returns true if we should install the extension
///
/// This will return true only when:
/// - Running in VS Code terminal
/// - Extension is not installed
pub fn should_install_extension() -> bool {
    is_vscode_terminal() && !is_extension_installed()
}

#[cfg(test)]
mod tests {
    use std::env;

    use super::*;

    fn with_env_var<F>(key: &str, value: &str, test: F)
    where
        F: FnOnce(),
    {
        // Set the environment variable
        // SAFETY: This is only used in single-threaded tests and cleaned up immediately
        // after
        unsafe {
            env::set_var(key, value);
        }

        // Run the test
        test();

        // Clean up
        // SAFETY: This is only used in single-threaded tests
        unsafe {
            env::remove_var(key);
        }
    }

    #[test]
    fn test_is_vscode_terminal_with_term_program() {
        with_env_var("TERM_PROGRAM", "vscode", || {
            assert!(is_vscode_terminal());
        });
    }

    #[test]
    fn test_is_vscode_terminal_with_vscode_pid() {
        with_env_var("VSCODE_PID", "12345", || {
            assert!(is_vscode_terminal());
        });
    }

    #[test]
    fn test_is_vscode_terminal_with_git_askpass() {
        with_env_var("VSCODE_GIT_ASKPASS_NODE", "/path/to/node", || {
            assert!(is_vscode_terminal());
        });
    }

    #[test]
    fn test_is_vscode_terminal_with_git_ipc() {
        with_env_var("VSCODE_GIT_IPC_HANDLE", "handle", || {
            assert!(is_vscode_terminal());
        });
    }

    #[test]
    fn test_should_install_when_in_vscode() {
        with_env_var("TERM_PROGRAM", "vscode", || {
            // We can't reliably test the actual installation check since it depends
            // on the actual VS Code installation, but we can verify the logic
            // when in VS Code terminal
            assert!(is_vscode_terminal());
        });
    }
}
